/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ihmprojet.core;

import ihmprojet.core.Events.ActionListener;
import ihmprojet.core.Events.NotificationActionEvent;
import ihmprojet.core.Events.SelectionChangedEvent;
import ihmprojet.core.historique.ActionInterface;
import ihmprojet.core.historique.AjouterOperateurBinaireAction;
import ihmprojet.core.historique.AjouterSommetAction;
import ihmprojet.core.historique.CopierSommetAction;
import ihmprojet.core.historique.HistoriqueManager;
import ihmprojet.core.historique.OperateurUnaireAction;
import ihmprojet.core.historique.SupprimerSommetAction;
import ihmprojet.core.model.Arrete;
import ihmprojet.core.model.DelegateTreeOperators;
import ihmprojet.core.model.Sommet;
import ihmprojet.core.model.Sommet.Type;
import ihmprojet.core.model.operateur.OperateurBinaire;
import ihmprojet.core.model.operateur.OperateurUnaire;
import ihmprojet.view.onglets.TypeNotificationEnum;
import javax.swing.event.EventListenerList;

/**
 *
 * @author Rémi PIOTAIX <remi.piotaix@gmail.com>
 * @author thomas
 */
public class Context {

    private DelegateTreeOperators tree;
    private HistoriqueManager hm = new HistoriqueManager();
    private final EventListenerList listeners = new EventListenerList();

    public Context() {
        tree = new DelegateTreeOperators();
        String desc = "Tâche racine de l'application. \nC'est la tâche de base à \n"
                + "laquelle vous pouvez rajouter \ndes tâches filles ainsi que\n des opérations"
                + ".\nPour plus de détail consulter \nle menu d'aide dans le \nsecond onglet.";
        Sommet root = new Sommet("Racine", Sommet.Type.ABSTRACTION, desc);
        tree.setRoot(root);
    }

    public void save() {
    }

    public static Context fromFile(String nomFich) {
        return null;
    }

    public void ajouterSommet(Sommet parent, String nom) {
        executerAction(new AjouterSommetAction(tree, parent, nom, ""));
        fireStateChanged("Add a new vertex.");
    }

    public void ajouterSommet(Sommet parent, String nom, Type type) {
        executerAction(new AjouterSommetAction(tree, parent, nom, "", type));
        fireStateChanged("Add a new vertex of " + type.name());
    }

    public void annuler() {
        if (hm.estAnnulable()) {
            hm.annuler();
            fireStateChanged("Cancel the last action.");
        } else {
            fireStateChanged("WARNING: Cant cancel your last action.");
        }
    }

    public void refaire() {
        if (hm.estRefeasable()) {
            hm.refaire();
            fireStateChanged("restore last action.");
        } else {
            fireStateChanged("WARNING: Cant restore your last action.");
        }
    }

    public boolean annulable() {
        return hm.estAnnulable();
    }

    public boolean refeasable() {
        return hm.estRefeasable();
    }

    public void supprimerSommet(Sommet sommet) {
        executerAction(new SupprimerSommetAction(tree, sommet));
        fireStateChanged("Suppresion of a task");
    }

    public void copierSommet(Sommet s) {
        executerAction(new CopierSommetAction(tree, s));
    }

    public void ajouterOperateurBinaire(Sommet s1, Sommet s2, OperateurBinaire opB) {
        AjouterOperateurBinaireAction aOBA = new AjouterOperateurBinaireAction(tree, s1, s2, opB);
        if (!aOBA.canExecute()) {
            fireStateChangedError(TypeNotificationEnum.errorSelect);
        }
        executerAction(aOBA);
    }

    public void ajouterOperateurUnaire(Sommet s, OperateurUnaire opU) {
        OperateurUnaire opTrouve = null;
        boolean trouve = false;
        for (OperateurUnaire op : s.getOpUnaires()) {
            if (opU.getType() == op.getType()) {
                trouve = true;
                opTrouve = op;
            }
        }
        if (trouve) {
            fireStateChanged("You delete an operator to the vertex " + s.getNom());
            this.supprimerOperateurUnaire(s, opTrouve);
        } else {
            actionOperateurUnaire(OperateurUnaireAction.Todo.AJOUTER, s, opU);
            fireStateChanged("Unary operator was add to the vertex " + s.getNom());
            s.sort();
        }
    }

    public void supprimerOperateurUnaire(Sommet s, OperateurUnaire opU) {
        actionOperateurUnaire(OperateurUnaireAction.Todo.SUPPRIMER, s, opU);
    }

    public void actionOperateurUnaire(OperateurUnaireAction.Todo sens, Sommet s, OperateurUnaire opU) {
        executerAction(new OperateurUnaireAction(sens, s, opU));
    }

    public void executerAction(ActionInterface action) {
        hm.executer(action);
        fireStateChanged(null);
    }

    public DelegateTreeOperators<Sommet, Arrete> getTree() {
        return tree;
    }

    public void addActionListener(ActionListener listener) {
        listeners.add(ActionListener.class, listener);
    }

    public void removeActionListener(ActionListener listener) {
        listeners.remove(ActionListener.class, listener);
    }

    public ActionListener[] getActionListeners() {
        return listeners.getListeners(ActionListener.class);
    }

    /**
     * signal de changement de sélection.
     */
    protected void fireSelectionChanged() {

        for (ActionListener listener : getActionListeners()) {
            SelectionChangedEvent sce = new SelectionChangedEvent();
            listener.fireChangementSelection(sce);

        }
    }

    protected void fireStateChanged(String ch) {

        for (ActionListener listener : getActionListeners()) {
            NotificationActionEvent nae = new NotificationActionEvent(ch);
            listener.fireNotificationChgmt(nae);
        }
    }

    protected void fireStateChangedError(TypeNotificationEnum ty) {

        for (ActionListener listener : getActionListeners()) {
            NotificationActionEvent nae = new NotificationActionEvent("");
            nae.setErreur(ty);
            listener.fireNotificationChgmt(nae);

        }
    }
}
